---@class Battle.Entity:Battle.Actor
---@field New fun():Battle.Entity
local Entity = Battle.CreateClass("Entity", Battle.Actor)
Battle.Entity = Entity

local tempVec3 = Vector3.New()

function Entity:OnCreate(param)
    if param== nil then
        param = {}
    end
    self.height = param.height or 3; --身高
    self.radius = param.radius or 0.5; --体宽半径
    self.modelId = param.modelId or 1;
    self.targetId = param.targetId or 0;
    self.modelName = param.modelName or ""
    self.rotateSpeed = param.rotateSpeed or 400;
    self.buffStateFlag = param.buffStateFlag or 0;
    self.skillStateFlag = param.skillStateFlag or 0;
    self.entityStateFlag = param.entityStateFlag or 0;
    self.totalStateFlag = param.totalStateFlag or 0;  -- 效果状态
    self.groupId = 0
    self.camp = param.camp or 0;
    self.equipSkillList = param.equipSkillList or {};--装配的技能
    ---@type Battle.EntityComponent[]
    self.components = {}
    self.area = 1
    self.createTime = 0--人物创建时间
    self.deadTime = 0
    self.deadState = 0
    self.isSummon = false   --是否召唤物
    self.hitDuringTime = 1
    self.isMoving = false
    ---@type Battle.EntityEventSystem
    self.eventSystem = self:AddComponent(Battle.EntityEventSystem)
    ---@type Battle.ActionStateSystem
    self.actionStateSystem = self:AddComponent(Battle.ActionStateSystem)
    ---@type Battle.EntityAttributeSystem
    self.attrSystem = self:AddComponent(Battle.EntityAttributeSystem)
    ---@type Battle.EntityGameObjectSystem
    self.gameObjectSystem =  self:AddComponent(Battle.EntityGameObjectSystem)


    ---@type Battle.EntityDamageSystem
    self.damageSystem = self:AddComponent(Battle.EntityDamageSystem)
    ---@type Battle.SkillSystem
    self.skillSystem = self:AddComponent(Battle.SkillSystem)
    ---@type Battle.EntityAiSystem
    self.aiSystem = self:AddComponent(Battle.EntityAiSystem)
    ---@type Battle.EntityEffectStateSystem
    self.effectStateSystem = self:AddComponent(Battle.EntityEffectStateSystem)
    ---@type Battle.EntitySignSystem
    self.signSystem = self:AddComponent(Battle.EntitySignSystem)
    self:AddComponent(Battle.EntityRoadArrowSystem)
    self:AddComponent(Battle.EntityHitSystem)


    self:EnterState(Battle.ActionState.idle)
end
function Entity:OnInitialize()
    local cfg = DataTable.GetById("t_hero", self.modelId)
    if not cfg then
        logError("找不到t_hero " .. self.modelId)
        return
    end
    local attr = decodeJsonStrToTable(cfg.f_HeroAttribute)
    self.attrSystem:SetBaseAttr(Battle.AttributeType.CRIT,15000)
    for k, v in pairs(attr) do
        self.attrSystem:SetBaseAttr(v[1],v[2])
    end
    self.searchRadius = cfg.f_SeekRange / 1000

    self.shapeType = cfg.f_HeroShape    --兵种体型
    self.unitType = cfg.f_HeroType      --兵种类型
    self.atkType = cfg.f_ArtType      --攻击类型

    if self.actorType == Battle.ActorType.Lord then
        self:AddComponent(Battle.SkillReadyEffComponent)
    end
    for k,v in pairs(self.components) do
        v:BaseInitialized()
    end
    if table.getn(self.equipSkillList )> 0 then
        for i, skillId in pairs(self.equipSkillList) do
            self.skillSystem:EquipSkill( skillId)
        end
    else
        self.skillSystem:EquipSkill(cfg.f_ArtID)--普攻技能id
        self.skillSystem:EquipSkill(cfg.f_SkillID)--技能1Id
        self.skillSystem:EquipSkill(cfg.f_Characteristic)--特性被动
    end
    for k,v in pairs(self.components) do
        v:BaseInitializedAfter()
    end
end
function Entity:OnDestroy()
    Battle.BufferMgr.RemoveBuffList(self.id)
    if self.components then
        for k, v in pairs(self.components) do
            v:BaseDestroy()
        end
    end
    self.components = nil

    self.actionStateSystem = nil
    self.skillSystem = nil
    self.eventSystem = nil
    self.attrSystem = nil
    self.damageSystem = nil
    self.gameObjectSystem = nil
end

function Entity:LoadModel()
    self.gameObjectSystem:LoadModel()
end
function Entity:IsMoving()
    return self.isMoving
end
function Entity:SetMoving(value)
    self.isMoving = value
end
function Entity:GetModelId()
    return self.modelId
end
function Entity:IsUnitFly()
    return self.unitType == Battle.UnitType.Fly
end
function Entity:IsUnitGround()
    return self.unitType ~= Battle.UnitType.Fly
end
function Entity:SetGrass(id,isIn)
    if self:IsUnitFly() then return end
    Battle.GrassMgr.SetGrass(self,id,isIn)
end
function Entity:SetGroup(groupId)
    self.groupId = groupId
end
function Entity:SetPos(x, y, z)
    Battle.Actor.SetPos(self,x,y,z)
    self.gameObjectSystem:SetPos(x,y,z)
    self.eventSystem:FireEvent(Battle.Event.ActorPosChanged, Battle.EventArgs.EntityArgs:Create(self))
end
function Entity:SetForward(x, y, z)
    Battle.Actor.SetForward(self, x, y, z)
    self.eventSystem:FireEvent(Battle.Event.ActorForwardChanged, Battle.EventArgs.EntityArgs:Create(self))
end
function Entity:GetActionState()
    return self.actionStateSystem.curActionState
end
function Entity:GetActionStateId()
    if self.actionStateSystem.curActionState then
        return self.actionStateSystem.curActionState.stateId
    end
    return Battle.ActionState.idle
end
function Entity:RotateTowards(forwardX,forwardY,forwardZ)
    self.gameObjectSystem:StartRotate(forwardX,forwardY,forwardZ)
end

function Entity:EnterState(stateId, data,forceExit)
    self.actionStateSystem:EnterState(stateId, data,forceExit)
end

function Entity:IsInIdle()
    if self:GetActionStateId() == Battle.ActionState.idle then
        return true
    end
    return false
end
---@return Battle.Entity
function Entity:GetTarget()
    return Battle.ActorManager.GetActor(self.targetId)
end
function Entity:ToString()
    return string.format("英雄: %d,配表id: %d,名字: %s",self.id,self.modelId,self.name)
end
---造成伤害
---@param damageData Battle.DamageData
function Entity:Damage(damageData)
    if Battle.ClientBattle.isBattleFinished then
        return
    end
    Battle.EventManager.notifyEventListener(Battle.BuffTriggerType.DAMAGE_FORT, self.id,damageData)
    self.eventSystem:FireEvent(Battle.Event.ActorDamageBefore,Battle.EventArgs.HitArgs:Create(damageData))
    self.eventSystem:FireEvent(Battle.Event.ActorDamageBeforeFinish,Battle.EventArgs.HitArgs:Create(damageData))
    damageData.target:Hurt(damageData)
    Battle.EventManager.notifyEventListener(Battle.BuffTriggerType.DAMAGE_BACK, self.id,damageData)
    self.eventSystem:FireEvent(Battle.Event.ActorDamageAfter,Battle.EventArgs.HitArgs:Create(damageData))

    --吸血
    local vam = self.attrSystem:GetVampire(damageData.damage)
    if vam > 0 then
        local data = Battle.BattleUtil.CreateDamageData(self,self,Battle.HurtType.Treat,-vam,false,damageData.sourceType,damageData.sourceId)
        self:Hurt(data)
    end
end
--受到伤害
---@param damageData Battle.DamageData
function Entity:Hurt(damageData)
    if Battle.ClientBattle.isBattleFinished then
        return
    end
    if self.isDead then
        return
    end
    local attacker = damageData.attacker
    Battle.EventManager.notifyEventListener(Battle.BuffTriggerType.HIT_DAMAGE_FORT,self.id,damageData)
    self.eventSystem:FireEvent(Battle.Event.ActorHitBefore,Battle.EventArgs.HitArgs:Create(damageData))
    self.eventSystem:FireEvent(Battle.Event.ActorHitBeforeFinish,Battle.EventArgs.HitArgs:Create(damageData))
    local hp = math.max(0, self:GetHp() - damageData.damage)
    if damageData.hurtType > 0 then
        self:SetHp(hp)
    end
    Battle.EventManager.notifyEventListener(Battle.BuffTriggerType.HIT_DAMAGE_BACK,self.id,damageData)
    self.eventSystem:FireEvent(Battle.Event.ActorHitAfter,Battle.EventArgs.HitArgs:Create(damageData))
    self.eventSystem:FireEvent(Battle.Event.PlayerHpChanged,Battle.EventArgs.EntityHpChangeArgs:Create(self,attacker))

    if damageData.hurtType > 0 then
        local showType = Battle.DamageShowType.Common
        if damageData.hurtType == Battle.HurtType.Treat then
            showType = Battle.DamageShowType.Treat
            Battle.EventManager.notifyEventByCampId(Battle.BuffTriggerType.FRIEND_RECOVERY_HEAlTH,self,damageData);
        elseif damageData.isCrit then
            showType = Battle.DamageShowType.Crit
        end
        self.eventSystem:FireEvent(Battle.Event.ActorDamageShow,Battle.EventArgs.EntityDamageShowArgs:Create(self,damageData.damage,showType))
    end
    self:CheckDead(attacker)

end
function Entity:CheckDead(attacker)
    if self:GetHp() <= 0 then
        self.skillSystem:EndAllSkill()
        self:SetDead()
        Battle.GrassMgr.LeaveGrass(self)
        self.deadTime = self.gameObjectSystem:GetClipLength("die")
        if self.deadTime == 0 then
            self.deadTime = 1
        end
        self.destroyTime = self.deadTime + 1
        self.deadState = 1
        self:EnterState(Battle.ActionState.failed)
        self.eventSystem:FireEvent(Battle.Event.ActorDead, Battle.EventArgs.EntityDeadArgs:Create(self,attacker))
        Battle.EventManager.notifyEventByCampId(Battle.BuffTriggerType.FRIEND_DEAD,self.camp);
        if self.actorType == Battle.ActorType.Lord then
            Battle.ClientBattle:BattleFinished()
        end
    end
end
-- 生命增减
---@param damage number
function Entity:LossHp(damage,attacker)
    if Battle.ClientBattle.isBattleFinished then
        return
    end
    if self.isDead then
        return
    end
    local hp = math.max(0, self:GetHp() - damage)
    self:SetHp(hp)
    self.eventSystem:FireEvent(Battle.Event.PlayerHpChanged,Battle.EventArgs.EntityHpChangeArgs:Create(self,nil))
    self.eventSystem:FireEvent(Battle.Event.ActorDamageShow,Battle.EventArgs.EntityDamageShowArgs:Create(self,damage, Battle.DamageShowType.Common))
    self:CheckDead(attacker)

end

function Entity:SetHp(hp)
    self.attrSystem:SetHp(hp,true)
end
function Entity:GetHp()
    return self.attrSystem:GetHp()
end
function Entity:GetHpMax()
    return self.attrSystem:GetHpMax()
end
function Entity:GetHeight()
    return self.height
end
function Entity:GetHPBarPos()
    local height = DataTable.GetById("t_hero",self.modelId,"f_BloodStrip")
    tempVec3:Set(self.pos.x ,self.pos.y + height/100,self.pos.z)
    return tempVec3
end
function Entity:GetHitPos()
    local height = DataTable.GetById("t_hero",self.modelId,"f_HitPosition")
    tempVec3:Set(self.pos.x ,self.pos.y + height/100,self.pos.z)
    return tempVec3
end
function Entity:Update(dt)
    self.createTime = self.createTime + dt;
    --self.area = Battle.SceneMgr.CheckInArea(self:GetPos())
    if self.isDead then
        self.deadTime = self.deadTime - dt
        self.destroyTime = self.destroyTime - dt
        if self.deadTime <= 0 then
            if self.deadState == 1 then
                Battle.BufferMgr.RemoveBuffList(self.id)
                self:EnterState(Battle.ActionState.idle)
                self.eventSystem:FireEvent(Battle.Event.ActorDeadAnimFinished)
            end
            self.deadState = 2
            if self.destroyTime <= 0 then
                Battle.ActorManager.DelayDestroyActor(self.id)
            end
        end
    end
    for k, v in pairs(self.components) do
        if (v:IsUpdate()) then
            v:Update(dt)
        end
    end

end
---@param sourceSender Battle.Entity buff来源
---source buff来源：skillId,buffId
function Entity:AddBuff(buffId, overlay, during,sourceSender,sourceSkillId,sourceBuffId)
    local mgr = Battle.BufferMgr
    local buff = mgr.GetBuff(self.id, buffId)
    if overlay == nil then overlay = 1 end
    if not buff then
        mgr.CreateBuff(buffId, overlay, self.id, during,sourceSender,sourceSkillId,sourceBuffId)
    else
        if buff.cfg.f_Superposition == Battle.BuffSuperposition.Replace then
            --替换
            buff:OnBuffRefresh(overlay)

        end
        buff:Set(buffId, overlay, self.id, during,sourceSender,sourceSkillId,sourceBuffId)
        buff:OnBuffRefresh(overlay)
    end
end
function Entity:RemoveBuff(buffId)
    Battle.BufferMgr.RemoveBuff(self.id, buffId)
end
function Entity:ClearBuff()
    Battle.BufferMgr.RemoveBuffList(self.id)
end
---@param actor Battle.Actor
function Entity:SetTarget(actor)
    if actor then
        self.targetId = actor:GetId()
    else
        self.targetId = 0
    end
end
function Entity:GetTarget()
    if self.targetId == 0 then
        return nil
    end
    return Battle.ActorManager.GetActor(self.targetId)
end
function Entity:HasTarget()
    if self.targetId == 0 then
        return false
    end
    local target = Battle.ActorManager.GetActor(self.targetId)
    return target ~= nil and not target:IsDead()
end
---@param actor Battle.Entity
function Entity:CanTarget(actor)
    if actor:IsDead() then
        return false
    end
    if not self.effectStateSystem:HasState(Battle.FighterStateEnum.SEE_HIDE) and actor.effectStateSystem:IsHide() then
        return false
    end
    if actor.effectStateSystem:HasState(Battle.FighterStateEnum.CAN_NOT_SELECT_BY_ENEMY) then
        return false
    end
    return true
end
--region component
---@return Battle.EntityComponent
---@param typeComponent Battle.EntityComponent
function Entity:AddComponent(typeComponent)
    local com = typeComponent.New()
    table.insert(self.components,com)
    com:BaseCreate(self)
    return com
end
---@return Battle.EntityComponent
function Entity:GetComponent(type)
    for k,v in pairs(self.components) do
        if v:GetType() == type then
            return v
        end
    end
    return nil
end
function Entity:RemoveComponent(type)
    for k,v in pairs(self.components) do
        if v:GetType() == type then
            v:BaseDestroy()
            table.remove(self.components,k)
            break
        end
    end
end
--endregion component
